#include <gmlib/cipher/aes.h>
#include <gmlib/cipher/mode.h>
#include <gmlib/err.h>
#include <gmlib/utils.h>
#include <memory.h>
#include <stdlib.h>

/* AES128 key */
static uint8_t gcm_key[] = {
    0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,  //
    0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08,  //
};

/* Unique initialisation vector */
static uint8_t gcm_iv[] = {
    0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
};

/* Example plaintext to encrypt */
static uint8_t gcm_pt[] = {
    0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,  //
    0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,  //
    0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,  //
    0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,  //
    0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,  //
    0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,  //
    0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,  //
    0xba, 0x63, 0x7b, 0x39,
};

/*
 * Example of Additional Authenticated Data (AAD), i.e. unencrypted data
 * which can be authenticated using the generated Tag value.
 */
static uint8_t gcm_aad[] = {
    0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed,
    0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2,
};

/* Expected ciphertext value */
static uint8_t gcm_ct[] = {
    0x61, 0x35, 0x3B, 0x4C, 0x28, 0x06, 0x93, 0x4A,  //
    0x77, 0x7F, 0xF5, 0x1F, 0xA2, 0x2A, 0x47, 0x55,  //
    0x69, 0x9B, 0x2A, 0x71, 0x4F, 0xCD, 0xC6, 0xF8,  //
    0x37, 0x66, 0xE5, 0xF9, 0x7B, 0x6C, 0x74, 0x23,  //
    0x73, 0x80, 0x69, 0x00, 0xE4, 0x9F, 0x24, 0xB2,  //
    0x2B, 0x09, 0x75, 0x44, 0xD4, 0x89, 0x6B, 0x42,  //
    0x49, 0x89, 0xB5, 0xE1, 0xEB, 0xAC, 0x0F, 0x07,  //
    0xC2, 0x3F, 0x45, 0x98,
};

/* Expected AEAD Tag value */
static uint8_t gcm_tag[] = {
    0x36, 0x12, 0xD2, 0xE7, 0x9E, 0x3B, 0x07, 0x85,
    0x56, 0x1B, 0xE1, 0x4A, 0xAC, 0xA2, 0xFC, 0xCB,
};

static uint8_t out[BLOCK_SIZE * 4];
static int outl;
static uint8_t tag[BLOCK_SIZE];

void test_mode_gcm2() {
    GCM_CTX ctx;
    AES_CTX aes_ctx;
    uint8_t* outptr;
    const CipherInfo* cipher = &AES128Info;

    // 加密测试
    outptr = out;
    gcm_init(gcm_key, gcm_iv, sizeof(gcm_iv), NULL, cipher, &aes_ctx, &ctx);
    gcm_update_aad(gcm_aad, sizeof(gcm_aad), &ctx);
    gcm_encrypt_update(outptr, &outl, gcm_pt, sizeof(gcm_pt), &ctx);
    outptr += outl;
    gcm_encrypt_final(outptr, &outl, tag, sizeof(gcm_tag), &ctx);
    outptr += outl;

    if (memcmp(tag, gcm_tag, sizeof(gcm_tag)) != 0 ||
        memcmp(out, gcm_ct, sizeof(gcm_ct)) != 0) {
        ERR_LOG("Err in aes_gcm");
        goto error;
    }

    return;
error:
    exit(-1);
}
